#pragma once
/*
 * kcp server test.
 */

#include "knet.h"
#include "log.h"
/*
#ifndef Debug
#define Debug printf
#endif
*/

class KSession : public KCP::IKSession {
public:
	KSession() : m_con(nullptr) {}
	virtual ~KSession() = default;

	// set connection
	virtual void GNAPI setConnection(KCP::IKConnection *conn) {
		m_con = conn;
	}

	// recv data callback.
	virtual bool GNAPI onRecv(const char *data, int len) {
		Adebug("receive {}", std::string(data, len).c_str());
		m_con->SendMsg(data, len);
		return true;
	}

	// connection close callback
	virtual void GNAPI onClose() {
		Adebug("{} close!", this);
	}

	// connection establish callback
	virtual void GNAPI onEstablish() {
		Adebug("{} establish, id: {}!\n", this, m_con->GetConv());
		m_con->SendMsg("hello", 5);
	}

	// release session.
	virtual void GNAPI release() {
		delete this;
	}

private:
	KCP::IKConnection *m_con;
};

class KSessionFactory : public KCP::IKSessionFactory {
public:
	KSessionFactory() = default;
	~KSessionFactory() = default;

	virtual KCP::IKSession* GNAPI CreateSession() {
		return new KSession();
	}
};


class KSession_Client : public KCP::IKSession {
public:
	KSession_Client() : m_con(nullptr) {}
	~KSession_Client() = default;

	// set connection
	virtual void GNAPI setConnection(KCP::IKConnection *conn) {
		m_con = conn;
	}

	// recv data callback.
	virtual bool GNAPI onRecv(const char *data, int len) {
		Adebug("receive {}", std::string(data, len).c_str());
		m_con->SendMsg(data, len);
		return true;
	}

	// connection close callback
	virtual void GNAPI onClose() {
		Adebug("{} close!", this);
	}

	// connection establish callback
	virtual void GNAPI onEstablish() {
		Adebug("{} establish, id: {}!\n", this, m_con->GetConv());
		m_con->SendMsg("world", 5);
	}

	// release session.
	virtual void GNAPI release() {
		delete this;
	}

private:
	KCP::IKConnection *m_con;
};

class KClientSessionFactory : public KCP::IKSessionFactory {
public:
	KClientSessionFactory() {}
	virtual ~KClientSessionFactory() {}
	virtual KCP::IKSession* GNAPI CreateSession() {
		return new KSession_Client();
	}
};

inline bool Start(const char *ip, unsigned short port) {
	KCP::IKcpModule *kcpModule = KCP::GetKcpModule();
	kcpModule->Init();
	return kcpModule->Listen(ip, port, new KSessionFactory);
}

inline bool Connect(const char *ip, unsigned short port) {
	KCP::IKcpModule *kcpModule = KCP::GetKcpModule();
	kcpModule->Init();
	return kcpModule->Connect(ip, port, new KClientSessionFactory);
}

inline void KCPRun(int count=-1) {
	KCP::IKcpModule *kcpModule = KCP::GetKcpModule();
	kcpModule->Run(count);
}